package persi.hibernate;

import java.io.Serializable;
import java.lang.reflect.Method;

import org.hibernate.Criteria;
import org.hibernate.classic.Session;
import org.hibernate.criterion.Restrictions;

import persi.entities.Entidad;
import persi.hibernate.exception.FutbolRuntimeException;

public class Home<T> {

	private final Class<T> entityType;

	public Home(final Class<T> entityType) {
		this.entityType = entityType;
	}

	public void borrar(final T object) {
		HibernateUtils.beginTransaction();
		getSession().delete(object);
	}

	@SuppressWarnings("unchecked")
	public T buscar(final Serializable id) {
		return (T) HibernateUtils.getSession().get(this.getEntityType(), id);
	}

	@SuppressWarnings("unchecked")
	public T buscar(final T example, final String... Properties) {
		final Criteria criteria = HibernateUtils.getSession().createCriteria(
				entityType);
		String currentProperty = "";
		try {
			for (final String property : Properties) {
				currentProperty = property;
				final Method getter = this.getEntityType().getDeclaredMethod(
						this.getGetterName(property), new Class<?>[] {});
				final boolean access = getter.isAccessible();
				getter.setAccessible(true);
				criteria.add(Restrictions.eq(property,
						getter.invoke(example, new Object[] {})));
				getter.setAccessible(access);
			}
			return (T) criteria.uniqueResult();
		} catch (final NoSuchMethodException e) {
			throw new FutbolRuntimeException(e, "El getter para \""
					+ currentProperty + "\" no existe");
		} catch (final Exception e) {
			throw new FutbolRuntimeException(e,
					"Problemas al recuperar el objeto pedido");
		}
	}

	private Class<T> getEntityType() {

		return this.entityType;
	}

	private String getGetterName(final String property) {
		return "get" + Character.toUpperCase(property.charAt(0))
				+ property.substring(1);
	}

	private Session getSession() {
		HibernateUtils.beginTransaction();
		return HibernateUtils.getSession();
	}

	public Serializable insertar(final T object) {
		final Serializable id = getSession().save(object);
		((Entidad) object).setId((Integer) id);
		return id;
	}

	public void actualizar(final T object) {
		getSession().update(object);
	}
	/**
	 * Fuerza a volcar los objetos a la base y cierra la sesion.-
	 */
	public void volcarADisco(){
		HibernateUtils.commit();
		HibernateUtils.getSession().flush();
		HibernateUtils.closeSession();
	}
}
